
// 模板编译(Vue方法： AST树 -> 虚拟节点 -> dom节点)
// 简单实现 -> 直接生成真实dom节点

const customTags = ['if', 'for'];
const reg_single_bracket = /\{(.+?)\}/g;
const reg_double_bracket = /\{\{(.+?)\}\}/g;

export function compileTemplate(template, data) { // 模板编译 -> 先把模板字符串变为节点
  // console.log(template, data);
  // 处理{{ xxx }} 里的内容
  template = replaceVar(template, data, reg_double_bracket);

  const _node = document.createElement('div');
  _node.innerHTML = template;
  // console.log(_node);
  return compileNode(_node, data);
}

function compileNode(node, data) { // 分析节点 并 添加到 app里的dom中
  const _allNodes = node.querySelectorAll('*');
  // console.log(_allNodes);
  _allNodes.forEach(item => {
    const tagName = item.tagName.toLowerCase();
    // console.log(tagName, item)
    // 把html的标签与自定义标签做区分
    if (customTags.includes(tagName)) { // 如果包含了自定义的节点就做替换
      replaceNode(item, tagName, data);
    }
  })
  // console.log(_allNodes);
  // console.log(node.childNodes);
  // 每个组件只有一个元素节点，找到元素节点并返回
  return [...node.childNodes].find(item => item.nodeType === 1);
}

function replaceNode(node, tag, data) { // 处理自定义标签内容
  const dataKey = node.getAttribute('data'),
        realTag = node.getAttribute('tag'),
        className = node.className;
  // console.log(dataKey, realTag, className, tag);
  switch (tag) {
    case 'for':
      vFor(node, data, dataKey, realTag, className);
      break;
    default:
      break;
  }
}

function vFor(node, data, dataKey, realTag, className) { // 处理for 标签
  // console.log(data[dataKey]);
  // 使用文档碎片包裹for循环内容 再 添加到dom中
  const oFarg = document.createDocumentFragment();

  data[dataKey].forEach(item => {
    // console.log(item, node);
    const html = node.innerHTML;
    // console.log(html);
    const el = document.createElement(realTag);
    el.className = className || '';
    el.innerHTML = replaceVar(html, item, reg_single_bracket);
    // console.log(el);
    oFarg.appendChild(el);
  })
  // console.log(oFarg);
  // console.log(node.parentNode);
  // 替换原来的node
  node.parentNode.replaceChild(oFarg, node);
}

function replaceVar(html, data, reg) { // 替换标签里的内容
  // console.log(html, data, reg);
  // console.log(html, html.match(reg), data)
  // 第一个参数是正则表达式，并且其为全局匹配模式，那么这个方法将被多次调用，每次匹配都会被调用
  return html.replace(reg, (node, key) => { // 使用一个函数把 { xxx } 替换
    // console.log(node, key);
    const obj = {};
    key = key.trim();
    return obj[key] = data[key];
  })
}
